home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / diskutil / fdf.zoo / sfdf.c < prev    next >
C/C++ Source or Header  |  1992-04-12  |  9KB  |  426 lines

  1. /*
  2.  * sfdf.c
  3.  *
  4.  * find duplicates.  searches a given path and its sub-directories for
  5.  * duplicate files.  Duplicate files have the same name, size, date and
  6.  * contents.  However, the definition used by this program can be any
  7.  * user-specified combination of the above.
  8.  *
  9.  * Roy Bixler (original development and Atari ST version)
  10.  * Ayman Barakat (idea)
  11.  * David Oertel (MS-DOS version)
  12.  *
  13.  * Version 1.0: March 11, 1991
  14.  * Version 1.01: April 12, 1992
  15.  *
  16.  * This program is free software; you can redistribute it and/or modify
  17.  * it under the terms of the GNU General Public License as published by
  18.  * the Free Software Foundation; either version 1, or (at your option)
  19.  * any later version.
  20.  *
  21.  * This program is distributed in the hope that it will be useful,
  22.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24.  * GNU General Public License for more details.
  25.  *
  26.  * You should have received a copy of the GNU General Public License
  27.  * along with this program; if not, write to the Free Software
  28.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29.  */
  30.  
  31.  
  32. #include <ctype.h>
  33. #include <osbind.h>
  34. #include <param.h>
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38.  
  39. #include "fdfcomm.h"
  40. #include "fdfstat.h"
  41. #include "elib.h"
  42. #include "sfdf.h"
  43.  
  44.  
  45.  
  46. /*
  47.  * print_help
  48.  *
  49.  * prints out the help message for the program
  50.  */
  51. void print_help()
  52.  
  53. {
  54.     printf(SFDF_USAGE, PROG_NAME, PROG_NAME);
  55. }
  56.  
  57.  
  58.  
  59. /*
  60.  * show_doc
  61.  *
  62.  * show full documentation
  63.  */
  64. void show_doc()
  65.  
  66. {
  67.     printf(SFDF_SCHPIEL1);
  68.     printf(SFDF_SCHPIEL2);
  69. }
  70.  
  71.  
  72.  
  73. /*
  74.  * sort_eq_match
  75.  *
  76.  * returns non-zero if the sort criteria is also one of the match criteria.
  77.  */
  78. int sort_eq_match()
  79.  
  80. {
  81.     return (((Sort_criteria & NAME_SORT) && (Match_criteria & NAMES_MATCH)) ||
  82.             ((Sort_criteria & SIZE_SORT) && (Match_criteria & SIZES_MATCH)) ||
  83.             ((Sort_criteria & TIME_SORT) && (Match_criteria & TIMES_MATCH)));
  84. }
  85.  
  86.  
  87.  
  88. /*
  89.  * print_dups
  90.  *
  91.  * given a pointer to a name which has been determined to be duplicated, print
  92.  * all the names and their path's out.  Return where a mismatch is found.
  93.  */
  94. void print_dups(FILE_LIST *start)
  95.  
  96. {
  97.     int n_found = 0;
  98.     long n_bytes = 0L;
  99.     FILE_LIST *cur;
  100.  
  101.     for (cur = start->next;
  102.          ((cur != NULL) && ((!sort_eq_match()) || (cmpflist_eq(start, cur))));
  103.          cur = cur->next)
  104.         if ((!cur->printed) && (files_match(start, cur))) {
  105.             if (!n_found++) {
  106.                 n_found++;
  107.                 if (v_flag)
  108.                     n_bytes += start->dta.dta_size;
  109.                 print_match_header(start);
  110.                 print_next_match(start, -1);
  111.             }
  112.             if (v_flag)
  113.                 n_bytes += cur->dta.dta_size;
  114.             print_next_match(cur, -1);
  115.         }
  116.  
  117.     if (n_found) {
  118.         if (v_flag) {
  119.             update_num_dups(n_found, n_bytes);
  120.             update_num_which_dupd();
  121.         }
  122.         printf("\n");
  123.     }
  124. }
  125.  
  126.  
  127.  
  128. /*
  129.  * gen_id_menu
  130.  *
  131.  * given a starting point in the file list, generate an interactive delete
  132.  * menu.  Return number of items put into the menu.
  133.  */
  134. int gen_id_menu(FILE_LIST *start, FILE_LIST **menu, int max_items)
  135.  
  136. {
  137.     int n_found = 0;
  138.     long n_bytes = 0L;
  139.     FILE_LIST *cur;
  140.  
  141.     for (cur = start->next;
  142.          ((cur != NULL) && (cmpflist_eq(start, cur)) && (n_found < max_items));
  143.          cur = cur->next)
  144.         if ((!cur->printed) && (files_match(start, cur))) {
  145.             if (n_found == 0) {
  146.                 if (v_flag)
  147.                     n_bytes += start->dta.dta_size;
  148.                 menu[n_found++] = start;
  149.             }
  150.             if (v_flag)
  151.                 n_bytes += cur->dta.dta_size;
  152.             menu[n_found++] = cur;
  153.         }
  154.  
  155.     if ((n_found) && (v_flag)) {
  156.         update_num_which_dupd();
  157.         update_num_dups(n_found, n_bytes);
  158.     }
  159.  
  160.     return n_found;
  161. }
  162.  
  163.  
  164.  
  165. /*
  166.  * id_dups
  167.  *
  168.  * given a pointer to a name which has been determined to be duplicated, print
  169.  * all the names and their path's out and ask the user which ones to delete.
  170.  */
  171. void id_dups(FILE_LIST *start)
  172.  
  173. {
  174.     int n_found, i, n_del;
  175.     FILE_LIST *cur, *menu[N_INTERACTIVE];
  176.     char menu_sel[MAX_STR], which_del[N_INTERACTIVE];
  177.  
  178.     if (!(n_found = gen_id_menu(start, menu, N_INTERACTIVE)))
  179.         return;
  180.     while (1) {
  181.         print_id_menu(menu, n_found);
  182.         printf("\nEnter list of files to delete (hit CR for none)\n");
  183.         fgets(menu_sel, MAX_STR-1, stdin);
  184.         zap_trailing_nl(menu_sel, MAX_STR-1, stdin);
  185.         if (!mark_list(menu_sel, which_del, n_found)) {
  186.             for (n_del=0, i=0; i < n_found; i++)
  187.                 if (which_del[i])
  188.                     if (!delete_path_name_file(menu[i]->path,
  189.                                                menu[i]->dta.dta_name, '\0')) {
  190.                         n_del++;
  191.                         if (v_flag) {
  192.                             update_total_del_bytes(menu[i]->dta.dta_size);
  193.                             if (v_flag > 1) {
  194.                                 printf("Deleted ");
  195.                                 print_fpath(menu[i]->path,
  196.                                             menu[i]->dta.dta_name);
  197.                                 printf("\n");
  198.                             }
  199.                         }
  200.                     }
  201.             break;
  202.         }
  203.     } 
  204.  
  205.     if (n_del)
  206.         printf("\n");
  207. }
  208.  
  209.  
  210.  
  211. /*
  212.  * find_non_printed
  213.  *
  214.  * given a pointer to a FILE_LIST, return the pointer to the next element which
  215.  * has not been printed yet.
  216.  */
  217. FILE_LIST *find_non_printed(FILE_LIST *file)
  218.  
  219. {
  220.     for (; ((file != NULL) && (file->printed)); file = file->next);
  221.     return file;
  222. }
  223.  
  224.  
  225.  
  226. /*
  227.  * find_dups
  228.  *
  229.  * given a path, find the duplicate files and dump them to the standard output.
  230.  */
  231. void find_dups()
  232.  
  233. {
  234.     FILE_LIST *f_found;
  235.  
  236.     for (f_found = F_list; (f_found != NULL);
  237.          f_found = find_non_printed(f_found->next))
  238.         if (i_flag)
  239.             id_dups(f_found);
  240.         else
  241.             print_dups(f_found);
  242. }
  243.  
  244.  
  245.  
  246. /*
  247.  * count_total_stats
  248.  *
  249.  * go back over the linked list and count the number of files and the total
  250.  * bytes in the files
  251.  */
  252. void count_total_stats()
  253.  
  254. {
  255.     FILE_LIST *cur;
  256.  
  257.     for (cur = F_list; cur != NULL; cur = cur->next) {
  258.         update_num_files();
  259.         update_total_bytes(cur->dta.dta_size);
  260.     }
  261. }
  262.  
  263.  
  264.  
  265. /*
  266.  * get_options
  267.  *
  268.  * get the command-line options, check for consistency and set the appropriate
  269.  * variables.
  270.  */
  271. int get_options(int argc, char **argv)
  272.  
  273. {
  274.     extern int getopt(int argc, char **argv, char *opts);
  275.     extern int Optind;
  276.     extern char *optarg;
  277.     int optchar;
  278.     char a_flag = 0, c_flag = 0, d_flag = 0, n_flag = 0, s_flag = 0;
  279.  
  280.     if (argc < 2) {
  281.         print_help();
  282.         exit(-1);
  283.     }
  284.  
  285.     while ((optchar = getopt(argc, argv, GETOPT_LIST)) != EOF) {
  286.         if (isupper(optchar))
  287.             optchar = tolower(optchar);
  288.         switch (optchar) {
  289.         case 'i':
  290.             i_flag = 1;
  291.             break;
  292.         case 'l':
  293.             l_flag = 1;
  294.             break;
  295.         case 'm':
  296.             if ((optarg == NULL) || (strpbrk(optarg, "AaCcDdNnSs") != optarg)) {
  297.                 printf("%s: must specify 'a' or 'c', 'd', 'n' and/or 's' after -m\n", 
  298.                        PROG_NAME);
  299.                 print_help();
  300.                 exit(-1);
  301.             }
  302.             for (;*optarg != '\0'; optarg++) {
  303.                 if (isupper(*optarg))
  304.                     *optarg = tolower(*optarg);
  305.                 switch (*optarg) {
  306.                 case 'a':
  307.                     a_flag = 1;
  308.                     break;
  309.                 case 'c':
  310.                     c_flag = 1;
  311.                     Match_criteria |= CONTENTS_MATCH;
  312.                     break;
  313.                 case 'd':
  314.                     d_flag = 1;
  315.                     Match_criteria |= TIMES_MATCH;
  316.                     break;
  317.                 case 'n':
  318.                     n_flag = 1;
  319.                     Match_criteria |= NAMES_MATCH;
  320.                     break;
  321.                 case 's':
  322.                     s_flag = 1;
  323.                     Match_criteria |= SIZES_MATCH;
  324.                     break;
  325.                 default:
  326.                     printf("%s: invalid match criteria '%c' specified\n", 
  327.                            PROG_NAME, *optarg);
  328.                     print_help();
  329.                     exit(-1);
  330.                 }
  331.             }
  332.             break;
  333.         case 'o':
  334.             if ((optarg == NULL) || (strpbrk(optarg, "AaDd") != optarg)) {
  335.                 printf("%s: must specify 'a' or 'd' after -o\n", PROG_NAME);
  336.                 print_help();
  337.                 exit(-1);
  338.             }
  339.             if (isupper(*optarg))
  340.                 *optarg = tolower(*optarg);
  341.             if (*optarg == 'a')
  342.                 Sort_order = ASCENDING;
  343.             else if (*optarg == 'd')
  344.                 Sort_order = DESCENDING;
  345.             break;
  346.         case 's':
  347.             if ((optarg == NULL) || (strpbrk(optarg, "DdNnSs") != optarg)) {
  348.                 printf("%s: must specify 'd', 'n' or 's' after -s\n",
  349.                        PROG_NAME);
  350.                 print_help();
  351.                 exit(-1);
  352.             }
  353.             if (isupper(*optarg))
  354.                 *optarg = tolower(*optarg);
  355.             switch (*optarg) {
  356.             case 'd':
  357.                 Sort_criteria = TIME_SORT;
  358.                 break;
  359.             case 'n':
  360.                 Sort_criteria = NAME_SORT;
  361.                 break;
  362.             case 's':
  363.                 Sort_criteria = SIZE_SORT;
  364.                 break;
  365.             }
  366.             break;
  367.         case 'v':
  368.             v_flag++;
  369.             break;
  370.         case '?':
  371.             show_doc();
  372.             exit(0);
  373.         default:
  374.             print_help();
  375.             exit(-1);
  376.         }
  377.     }
  378.  
  379.     if (argc == Optind) {
  380.         printf("%s: at least one path specification required\n", PROG_NAME);
  381.         print_help();
  382.         exit(-1);
  383.     }
  384.     else if (a_flag)
  385.         if ((c_flag) || (d_flag) || (n_flag) || (s_flag)) {
  386.             printf("%s: -ma option conflicts with -mc, -md, -mn or -ms\n",
  387.                    PROG_NAME);
  388.             print_help();
  389.